package com.eningqu.aipen.demo.view;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;

import com.blankj.utilcode.util.LogUtils;
import com.blankj.utilcode.util.ToastUtils;
import com.eningqu.aipen.demo.R;
import com.eningqu.aipen.demo.bean.NQStroke;
import com.eningqu.aipen.sdk.bean.DotType;
import com.eningqu.aipen.sdk.bean.NQDot;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import androidx.core.content.ContextCompat;

/**
 * @Author: Qiu.Li
 * @Create Date: 2020/3/8 14:43
 * @Description: 绘制视图, 继承与surfaceView
 */
public class CanvasDrawView extends SurfaceView implements SurfaceHolder.Callback, Runnable {

    private Canvas canvas;
    private SurfaceHolder mHolder;
    //    DrawHelper drawHelper;
    private Context mContext = null;
    int systemState = 0;

    private final int MAX_DIST_TOW_POINTS = 250;//两点之间最大值

    final ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
    /**
     * 屏幕手绘开关
     */
    private boolean mTouchDrawSwitch = false;

    //子线程绘制标记
    private volatile boolean isDrawing;
    private volatile boolean isDrawing2;

    private static final boolean GESTURE_RENDERING_ANTIALIAS = true;
    private static final boolean DITHER_FLAG = true;

    private Paint mPaint = null;
    private Path mPath = new Path();
    private int mPenSize = 2;
    private int mPenColor;

    Matrix matrix = new Matrix();

    private String curMac = "all";
    /**
     * 所有笔绘制的笔画
     */
    Map<String, List<NQStroke>> allStrokes = new LinkedHashMap<>();
    /**
     * 所有笔当前笔画
     */
    Map<String, NQStroke> allCurStrokes = new LinkedHashMap<>();
    /**
     * 所有笔当前笔上一个点
     */
    volatile Map<String, NQDot> allLastNQDot = new LinkedHashMap<>();
    /**
     * 单支笔的所有笔画
     */
    private ArrayList<NQStroke> strokes = new ArrayList<>();
    /**
     * 单支笔的当前笔画
     */
    NQStroke curStroke = new NQStroke();

    //设置一个默认值
    private Bitmap mBmpBg = null;

    public CanvasDrawView(Context context) {
        super(context);
        init(context);
    }

    public CanvasDrawView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context context) {
        this.mContext = context;
        SurfaceHolder holder = getHolder();//获取到Surface的Holder，控制器
        holder.addCallback(this);
        mHolder = holder;
//        drawHelper = new DrawHelper(holder, context);
        setFocusable(true);

        setWillNotDraw(false);
        mPenColor = ContextCompat.getColor(mContext, R.color.color_000000);

        //设置默认的背景
        mBmpBg= BitmapFactory.decodeResource(getResources(),R.drawable.bg_west);

        createPaint();//创建画笔
        mPath.reset();
    }

    //获取当前屏幕上的bitmap
    //利用了compress函数压缩图片格式为png
    public Bitmap getCurrentBitmap() {
        if (mBmpBg != null) {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            mBmpBg.compress(Bitmap.CompressFormat.PNG, 100, bos);
            byte[] bytes = bos.toByteArray();
            return BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
        }
        return null;
    }

    private void createPaint() {
        mPaint = new Paint();
        mPaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS);
        mPaint.setColor(mPenColor);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND);
        mPaint.setStrokeCap(Paint.Cap.ROUND);
        mPaint.setStrokeWidth(mPenSize);
        mPaint.setDither(DITHER_FLAG);
    }

    public void setColor(int color) {
        this.mPenColor = color;
        mPaint.setColor(color);
    }


    public void setSize(int size) {
        this.mPenSize = size;
        mPaint.setStrokeWidth(size);
    }

    @Override
    public Matrix getMatrix() {
        return matrix;
    }

    public void setMatrix(Matrix matrix) {
        this.matrix = matrix;
    }

    /**
     * 第一次创建时调用
     * 负责通过单线程池创建一个线程
     *
     * @param holder
     */
    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        LogUtils.d("surfaceCreated()");
        if (systemState == 0) {
////            drawHelper.canRun = true;
////            drawHelper.canRun2 = true;
            isDrawing2 = true;
            singleThreadExecutor.execute(new Thread(this));
        } else {
//            // drawHelper.PauseNResume(false);
////            drawHelper.canRun2 = true;
            isDrawing2 = true;
//            systemState = 1;
        }
    }

    /**
     * Surface的状态变化时调用
     *
     * @param holder
     * @param format
     * @param width
     * @param height
     */
    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
                               int height) {
        // TODO Auto-generated method stub
        LogUtils.d("surfaceChanged()");
    }

    /**
     * Surface被销毁时调用
     *
     * @param holder
     */
    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        // TODO Auto-generated method stub
        LogUtils.d("surfaceDestroyed()");
        isDrawing2 = false;
    }

    /*
     * 界面触摸
     *
     * @param event
     * @return
     * */
    /*public boolean onTouchEvent(MotionEvent event) {
        if (event.getAction() == MotionEvent.ACTION_DOWN) {
            if (mTouchDrawSwitch) {
                synchronized (mHolder) {
                    int x = (int) event.getX();
                    int y = (int) event.getY();
                    //drawHelper.ProcessTouchScreen(x, y);
                    drawHelper.drawTouchDownProcess(x, y);
                }
            }
        } else if (event.getAction() == MotionEvent.ACTION_MOVE) {
            if (mTouchDrawSwitch) {
                synchronized (mHolder) {
                    int x = (int) event.getX();
                    int y = (int) event.getY();
                    //drawHelper.ProcessTouchScreen(x, y);
                    drawHelper.drawTouchMoveProcess(0, x, y);
                }
            }
        } else if (event.getAction() == MotionEvent.ACTION_UP) {
            if (mTouchDrawSwitch) {
                synchronized (mHolder) {
                    int x = (int) event.getX();
                    int y = (int) event.getY();
                    //drawHelper.ProcessTouchScreen(x, y);
                    drawHelper.drawTouchMoveUpProcess(x, y);
                }
            }
        }
        return true;
    }*/

    /**
     * 设置背景
     *
     * @param bmp
     */
    public void setBackImage(Bitmap bmp) {
//        if (bmp != null && null != drawHelper)
//            drawHelper.setBackImage(bmp);

        this.mBmpBg = bmp;
    }

    /**
     * 子线程中执行具体的绘制笔迹
     */
    @Override
    public void run() {
        while (isDrawing) {
            draw();
            try {
                Thread.sleep(80);//不需要太过频繁的调用draw，节省资源
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

    }

    public void setDrawing(boolean drawing) {
        this.isDrawing = drawing;
    }


    private void draw() {

        synchronized (this) {
            if (isDrawing) {
                try {
                    //通过lockCanvas()方法获得Canvas对象进行绘制
                    canvas = mHolder.lockCanvas();

                    if (null == canvas) {
                        return;
                    }
                    if (null != matrix) {
                        canvas.setMatrix(matrix);
                    }

                    //绘制背景
                    canvas.drawColor(Color.WHITE, PorterDuff.Mode.SRC);
                    if (null != mBmpBg) {
                        canvas.drawBitmap(mBmpBg, null, new Rect(0, 0, getWidth(), getHeight()), null);
                    }

                    //执行具体的绘制操作
                    /*for (int i = 0; i < strokes.size(); i++) {
                        if (strokes.get(i).fullPath != null) {

                            Paint paint = strokes.get(i).paint;
                            if (null != paint) {
                                canvas.drawPath(strokes.get(i).fullPath, paint);
                            } else {
                                canvas.drawPath(strokes.get(i).fullPath, mPaint);
                            }
                        }
                    }
                    if (curStroke.fullPath != null)
                        canvas.drawPath(curStroke.fullPath, mPaint);*/

                    //执行所有笔具体的绘制操作
                    foreachStrokes(canvas);

                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    if (canvas != null) {
                        //通过unlockCanvasAndPost方法对画布内容进行提交
                        mHolder.unlockCanvasAndPost(canvas);
                    }
                }
            }
        }
    }

    /**
     * 遍历所有笔画
     *
     * @param canvas
     */
    private void foreachStrokes(Canvas canvas) {
        Iterator entriesAllStrokes = allStrokes.entrySet().iterator();
        Iterator entriesAllCurStrokes = allCurStrokes.entrySet().iterator();

        int i = 0;
        //遍历所有笔
        NQStroke nqStroke;
        while (entriesAllStrokes.hasNext()) {
            Map.Entry entry = (Map.Entry) entriesAllStrokes.next();
            String mac = (String) entry.getKey();
            ArrayList<NQStroke> strokes = (ArrayList<NQStroke>) entry.getValue();
            if (strokes.size() > 0 && ("all".equals(curMac) || (!"all".equals(curMac) && curMac.equals(mac)))) {
                //遍历所有笔画
                //执行具体的绘制操作
                for (i = 0; i < strokes.size(); i++) {
                    Log.i("lixu", "foreachStrokes: 遍历所有笔 ");

                    nqStroke = strokes.get(i);
                    if (null != nqStroke && nqStroke.fullPath != null) {

                        Paint paint = strokes.get(i).paint;
                        if (null != paint) {
                            canvas.drawPath(strokes.get(i).fullPath, paint);
                        } else {
                            canvas.drawPath(strokes.get(i).fullPath, mPaint);
                        }
                    }
                }
            }

            //绘制当前笔的当前笔画
            NQStroke curStrokes = allCurStrokes.get(mac);
            if (null != curStrokes) {
                if (null != curStrokes && curStrokes.fullPath != null)
                    Log.i("lixu", "foreachStrokes: 绘制当前笔的当前笔画 ");
                    canvas.drawPath(curStrokes.fullPath, mPaint);
            }
        }
    }

    public void showStrokesByMac(String mac) {
        Log.d("test", "set mac=" + mac);
        this.curMac = mac;
    }

    public void updateView() {
        invalidate();
    }

    public void cleanCanvas() {

        if (null != strokes) {
            strokes.clear();
        }

        if (null != curStroke && null != curStroke.getDots()) {
            curStroke.getDots().clear();
        }

        if (null != allStrokes) {
            allStrokes.clear();
        }

        if (null != allCurStrokes) {
            allCurStrokes.clear();
        }
        invalidate();
    }

    public List<NQStroke> getStrokes() {
        return this.strokes;
    }

    /**
     * 根据盒子地址返回笔画列表
     *
     * @param mac
     * @return
     */
    private List<NQStroke> getStrokesByMac(String mac) {
        if (allStrokes.containsKey(mac)) {
            //存在
            return allStrokes.get(mac);
        }

        List<NQStroke> strokeList = new ArrayList<>();
        allStrokes.put(mac, strokeList);

        return strokeList;
    }

    private NQStroke getCurStrokeByMac(String mac) {

        if (allCurStrokes.containsKey(mac)) {
            return allCurStrokes.get(mac);
        }

        NQStroke curNQStroke = new NQStroke();
        allCurStrokes.put(mac, curNQStroke);

        return curNQStroke;
    }

    private void createCurNQStroke(String mac) {
        NQStroke curNQStroke = new NQStroke();
        LogUtils.d("创建新到当前笔画Mac=" + mac + ", curNQStroke=" + curNQStroke);
        allCurStrokes.put(mac, curNQStroke);
        removeLastNQDotByMac(mac);
    }

    private NQDot getLastNQDotByMac(String mac) {
        if (allLastNQDot.containsKey(mac)) {
            return allLastNQDot.get(mac);
        }

        return null;
    }

    private void removeLastNQDot(String key, Object object) {
        LogUtils.d("remove last Dot");
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            allLastNQDot.remove(key, object);
        } else {
            allLastNQDot.remove(key);
        }
    }

    private void removeLastNQDotByMac(String key) {
        LogUtils.d("remove last Dot by mac");
        allLastNQDot.remove(key);
    }

    private void setLastNQDot(String mac, NQDot nqDot) {
        allLastNQDot.put(mac, nqDot);
    }

    /**
     * 单支笔时添加点
     *
     * @param dot
     */
    public void addDot(NQDot dot) {
        curStroke.add(dot);
        curStroke.buildBezierPath(getWidth(), getHeight(), mPaint);
        if (dot.type != DotType.PEN_ACTION_UP) {

        } else {
            strokes.add(curStroke);
            curStroke = new NQStroke();
            createPaint();
        }
        invalidate();
    }

    /**
     * 多支笔时添加点
     *
     * @param mac
     * @param dot
     */
    public synchronized void addDot(String mac, NQDot dot) {

        boolean giveUp = giveUpDot(mac, dot);
        if (giveUp && dot.type == DotType.PEN_ACTION_MOVE) {
            return;
        }

        //缓存当前点
        if (!giveUp) {
            setLastNQDot(mac, dot);
        }
        //获取当前mac的笔画列表
        List<NQStroke> strokeList = getStrokesByMac(mac);
        //获取当前mac的当前笔画
        NQStroke curNQStroke = getCurStrokeByMac(mac);
        //把点添加给当前笔画
        if (!giveUp) {
            curNQStroke.add(dot);
        }
        //绘制贝塞尔曲线
        curNQStroke.buildBezierPath(getWidth(), getHeight(), mPaint);

        if (dot.type == DotType.PEN_ACTION_UP) {
            //抬笔时
            strokeList.add(curNQStroke);
//            curStroke = new NQStroke();
            createCurNQStroke(mac);
            createPaint();
        }
    }

    /**
     * 单支笔 ,添加多个点
     *
     * @param dots
     */
    public void addDots(List<NQDot> dots) {
        curStroke = new NQStroke();
        for (int i = 0; i < dots.size(); i++) {
            NQDot dot = dots.get(i);
            curStroke.add(dot);
            if (dot.type != 2) {

            } else {
                curStroke.buildBezierPath(getWidth(), getHeight(), mPaint);
                strokes.add(curStroke);
                curStroke = new NQStroke();
                createPaint();
            }
        }
        invalidate();
    }


    /**
     * 过滤飞点
     *
     * @param mac
     * @param dot
     * @return
     */
    private boolean giveUpDot(String mac, NQDot dot) {

        NQDot lastDot = getLastNQDotByMac(mac);
        if (null == lastDot || dot.type == DotType.PEN_ACTION_DOWN
                || dot.type == DotType.PEN_ACTION_UP || lastDot.x == 0 || lastDot.y == 0) {
            return false;
        }

        double a = Math.pow(Math.abs(dot.x - lastDot.x), 2);
        double b = Math.pow(Math.abs(dot.y - lastDot.y), 2);
        double dist = Math.sqrt(a + b);
//                    if(dist>2){
//                        LogUtils.e("distant", "distant to last dot dist="+dist + "=Math.sqrt("+a+"+"+b+")" + ", lastDot.x="
//                                +mLastDot.x+", lastDot.y="+mLastDot.y+", current dot.x="+dot.x+", dot.y="+dot.y);
//                    }
//                    else {
//                        LogUtils.d("distant", "distant to last dot dist="+dist + "=Math.sqrt("+a+"+"+b+")" + ", lastDot.x="
//                                +mLastDot.x+", lastDot.y="+mLastDot.y+", current dot.x="+dot.x+", dot.y="+dot.y);
//                    }
        //过滤飞点
        if (dist > MAX_DIST_TOW_POINTS) {
            LogUtils.e("dot exception dist=" + dist + ", lastDot.x="
                    + lastDot.x + ", lastDot.y=" + lastDot.y + ", current dot.x=" + dot.x + ", dot.y=" + dot.y);
            return true;
        }
        return false;
    }
}



